package com.lixinlei.meetingfilm.gw.predicates;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.List;
import java.util.function.Predicate;
import javax.validation.constraints.NotEmpty;
import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
import org.springframework.web.server.ServerWebExchange;

/**
 * 日期路由自定义
 * 一定一定要注意：RoutePredicateFactory为结尾，RoutePredicateFactory 之前的内容，就是写在 application.yml 中的 key
 * 思路：
 * 1）写一个类继承 AbstractRoutePredicateFactory，泛型指定了用来装 application.yml 中参数值的是哪个类；
 * 2）这个类的名字必须以 RoutePredicateFactory 为结尾，RoutePredicateFactory 之前的内容就是 application.yml 中 predicates 的 key；
 * 3）shortcutFieldOrder 方法指明了，application.yml 中的参数值存储在泛型类中的哪个属性；
 * 4）apply 方法，实现了匹配规则；请求来了，如果配这个类的规则匹配到了，就代理到其 uri 指定的地方去；
 */
public class JiangzhAfterRoutePredicateFactory extends AbstractRoutePredicateFactory<JiangzhAfterRoutePredicateFactory.Config> {

    public static final String AFTER_KEY = "datetime";

    /**
     * 传入配置信息
     */
    public JiangzhAfterRoutePredicateFactory() {
        super(JiangzhAfterRoutePredicateFactory.Config.class);
    }

    /**
     * 参数列表与 Config 属性之间的映射
     * @return
     */
    @Override
    public List<String> shortcutFieldOrder() {
        // 这里填进去的是 Config 属性的名字
        return Collections.singletonList(AFTER_KEY);
    }

    /**
     * 具体的路由匹配逻辑
     * 如果返回 true，就匹配到了这个路由；如果返回 false，就没有匹配到这路由；
     * @param config 从 application.yml 中读取到的配置
     * @return
     */
    @Override
    public Predicate<ServerWebExchange> apply(Config config) {
        System.out.println("JiangzhAfterRoutePredicateFactory -> config : " + config);
        DateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        long nowTime = System.currentTimeMillis();
        return (exchange) -> {
            // 解析出配置定义的时间
            long afterTime = 0;
            try {
                afterTime = format.parse(config.getDatetime()).getTime();
            } catch (ParseException e) {
                return false;
            }
            // 如果当前时间大于配置定义时间，则返回true
            return nowTime > afterTime;
        };
    }

    /**
     * 用于承载 predicate 所需的参数
     * 我们这里是判断输入的时间与真实时间之间的先后关系
     */
    public static class Config {
        @NotEmpty
        private String datetime;

        public Config() {}

        public String getDatetime() {
            return datetime;
        }

        public void setDatetime(String datetime) {
            this.datetime = datetime;
        }
    }

}
